package com.lefu.risk.storm.utils;


import java.io.Serializable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisSentinelPool;


public class JedisPoolUtil implements Serializable{

	private static final long serialVersionUID = 1L;

	private static Map<String, Object> poolMap = new HashMap<String, Object>();

	protected Jedis jedis;

	private String propertiesName = null;
	/**
	 * 根据传入的properties文件名称获得或创建相应jedis链接池并获得链接
	 * @param propertiesName
	 */
	public JedisPoolUtil(String propertiesName) {
		JedisSentinelPool pool = initPool(propertiesName);
		jedis = pool.getResource();
	}

	public Jedis getResource() {
		return jedis;
	}

	/**
	 * 初始化Jedis连接池
	 * @Description 一句话描述方法用法
	 * @param propertiesName
	 */
	public static JedisSentinelPool initPool(String propertiesName) {
		if (poolMap.get(propertiesName) == null) {
			PropertyUtil propertyUtil = PropertyUtil.getInstance(propertiesName);

			String host = propertyUtil.getProperty("redis.host");

			String mystername = propertyUtil.getProperty("redis.master.name");

			//String password = propertyUtil.getProperty("redis.password");

			String dbIndex = propertyUtil.getProperty("redis.dbIndex");

			String timeout = propertyUtil.getProperty("redis.connection.timeout");

			String maxWaitMillis = propertyUtil.getProperty("redis.pool.maxWaitMillis");

			String maxTotal = propertyUtil.getProperty("redis.pool.maxTotal");

			String minIdle = propertyUtil.getProperty("redis.pool.minIdle");

			String maxIdle = propertyUtil.getProperty("redis.pool.maxIdle");

			String whenExhaustedAction = propertyUtil.getProperty("redis.pool.whenExhaustedAction");

			String testOnBorrow = propertyUtil.getProperty("redis.pool.testOnBorrow");

			String testOnReturn = propertyUtil.getProperty("redis.pool.testOnReturn");

			String testWhileIdle = propertyUtil.getProperty("redis.pool.testWhileIdle");

			String minEvictableIdleTimeMillis = propertyUtil.getProperty("redis.pool.minEvictableIdleTimeMillis");

			String timeBetweenEvictionRunsMillis = propertyUtil.getProperty("redis.pool.timeBetweenEvictionRunsMillis");

			String numTestsPerEvictionRun = propertyUtil.getProperty("redis.pool.numTestsPerEvictionRun");

			String softMinEvictableIdleTimeMillis = propertyUtil.getProperty("redis.pool.softMinEvictableIdleTimeMillis");

			String lifo = propertyUtil.getProperty("redis.pool.lifo");

			// redis sentinel链接
			Set<String> sentinels = new HashSet<String>();

			for (int i = 0; i < host.split(";").length; i++) {
				sentinels.add(host.split(";")[i]);
			}
			GenericObjectPoolConfig config = new GenericObjectPoolConfig();
			// 如果赋值为-1，则表示不限制；如果pool已经分配了maxActive个jedis实例，则此时pool的状态为exhausted(耗尽)。
			config.setMaxTotal(Integer.valueOf(maxTotal));
			// 控制一个pool最多有多少个状态为idle(空闲的)的jedis实例。
			config.setMaxIdle(Integer.valueOf(maxIdle));
			// 表示当borrow(引入)一个jedis实例时，最大的等待时间，如果超过等待时间，则直接抛出JedisConnectionException；
			config.setMaxWaitMillis(Long.valueOf(maxWaitMillis));
			// 在borrow一个jedis实例时，是否提前进行validate操作；如果为true，则得到的jedis实例均是可用的；
			config.setTestOnBorrow(Boolean.valueOf(testOnBorrow));
			JedisSentinelPool pool = new JedisSentinelPool(mystername, sentinels, config, Integer.valueOf(timeout), null, Integer.valueOf(dbIndex));
			// 将jedis连接池保存至静态变量中
			poolMap.put(propertiesName, pool);
			return pool;
		} else {
			JedisSentinelPool pool = (JedisSentinelPool) poolMap.get(propertiesName);
			return pool;
		}
	}

	/**
	 * 返还jedis链接
	 * @Description 一句话描述方法用法
	 */
	public void close() {
		if (jedis != null) {
			jedis.close();
		}
	}

	public Long del(String... keys) {
		Long l = jedis.del(keys);
		return l;
	}

	public String set(String key, String value) {
		String str = jedis.set(key, value);
		return str;
	}

	public String set(int seconds, String key, String value) {
		String str = jedis.set(key, value);
		jedis.expire(key, seconds);
		return str;
	}

	public Long setnx(int seconds, String key, String value) {
		Long l = jedis.setnx(key, value);
		if (l != 0) {
			jedis.expire(key, seconds);
		}
		return l;
	}

	public Long setnx(String key, String value) {
		Long l = jedis.setnx(key, value);
		return l;
	}

	public String setex(int seconds, String key, String value) {
		String str = jedis.setex(key, seconds, value);
		return str;
	}

	public Long setrange(String key, Long offset, String value) {
		Long l = jedis.setrange(key, offset, value);
		return l;
	}

	public String get(String key) {
		String str = jedis.get(key);
		return str;
	}

	public String mset(String... keysvalues) {
		String str = jedis.mset(keysvalues);
		return str;
	}

	public Long msetnx(String... keysvalues) {
		Long l = jedis.msetnx(keysvalues);
		return l;
	}

	public String getset(int seconds, String key, String value) {
		String str = jedis.getSet(key, value);
		jedis.expire(key, seconds);
		return str;
	}

	public String getset(String key, String value) {
		String str = jedis.getSet(key, value);
		return str;
	}

	public String getrange(String key, Long startOffset, Long endOffset) {
		String str = jedis.getrange(key, startOffset, endOffset);
		return str;
	}

	public List<String> mget(String... keys) {
		List<String> list = jedis.mget(keys);
		return list;
	}

	public Long sadd(int seconds, String key, String... members) {
		Long l = jedis.sadd(key, members);
		jedis.expire(key, seconds);
		return l;
	}

	public Long sadd(String key, String... members) {
		Long l = jedis.sadd(key, members);
		return l;
	}

	public Set<String> smembers(String key) {
		Set<String> set = jedis.smembers(key);
		return set;
	}

	public Long srem(String key, String... members) {
		Long l = jedis.srem(key, members);
		return l;
	}

	public String spop(String key) {
		String str = jedis.spop(key);
		return str;
	}

	public Set<String> sdiff(String... keys) {
		Set<String> set = jedis.sdiff(keys);
		return set;
	}

	public Long sdiffstore(String dstkey, String... keys) {
		Long l = jedis.sdiffstore(dstkey, keys);
		return l;
	}

	public Long sdiffstore(String dstkey, int seconds, String... keys) {
		Long l = jedis.sdiffstore(dstkey, keys);
		jedis.expire(dstkey, seconds);
		return l;
	}

	public Set<String> sinter(String... keys) {
		Set<String> set = jedis.sinter(keys);
		return set;
	}

	public Long sinterstore(String dstkey, String... keys) {
		Long l = jedis.sinterstore(dstkey, keys);
		return l;
	}

	public Long sinterstore(String dstkey, int seconds, String... keys) {
		Long l = jedis.sinterstore(dstkey, keys);
		jedis.expire(dstkey, seconds);
		return l;
	}

	public Set<String> sunion(String... keys) {
		Set<String> set = jedis.sunion(keys);
		return set;
	}

	public Long sunionstore(String dstkey, String... keys) {
		Long l = jedis.sunionstore(dstkey, keys);
		return l;
	}

	public Long sunionstore(String dstkey, int seconds, String... keys) {
		Long l = jedis.sunionstore(dstkey, keys);
		jedis.expire(dstkey, seconds);
		return l;
	}

	public Long smove(String srckey, String dstkey, String member) {
		Long l = jedis.smove(srckey, dstkey, member);
		return l;
	}

	public Long scard(String key) {
		Long l = jedis.scard(key);
		return l;
	}

	public Boolean sismember(String key, String member) {
		Boolean flag = jedis.sismember(key, member);
		return flag;
	}

	public String srandmember(String key) {
		String str = jedis.srandmember(key);
		return str;
	}

	public Long strlen(String key) {
		Long l = jedis.strlen(key);
		return l;
	}

	public Long incr(int seconds, String key) {
		Long l = jedis.incr(key);
		jedis.expire(key, seconds);
		return l;
	}

	public Long incr(String key) {
		Long l = jedis.incr(key);
		return l;
	}

	public Long incrby(int seconds, String key, Long integer) {
		Long l = jedis.incrBy(key, integer);
		jedis.expire(key, seconds);
		return l;
	}

	public Long incrby(String key, Long integer) {
		Long l = jedis.incrBy(key, integer);
		return l;
	}

	public Long decr(int seconds, String key) {
		Long l = jedis.decr(key);
		jedis.expire(key, seconds);
		return l;
	}

	public Long decr(String key) {
		Long l = jedis.decr(key);
		return l;
	}

	public Long decrby(int seconds, String key, Long integer) {
		Long l = jedis.decrBy(key, integer);
		jedis.expire(key, seconds);
		return l;
	}

	public Long decrby(String key, Long integer) {
		Long l = jedis.decrBy(key, integer);
		return l;
	}

	public Long append(String key, String value) {
		Long l = jedis.append(key, value);
		return l;
	}

	public Long lpush(int seconds, String key, String... strings) {
		Long l = jedis.lpush(key, strings);
		jedis.expire(key, seconds);
		return l;
	}

	public Long lpush(String key, String... strings) {
		Long l = jedis.lpush(key, strings);
		return l;
	}

	public Long rpush(String key, String... strings) {
		Long l = jedis.rpush(key, strings);
		return l;
	}

	public Long rpush(int seconds, String key, String... strings) {
		Long l = jedis.rpush(key, strings);
		jedis.expire(key, seconds);
		return l;
	}

	public String lset(String key, Long index, String value) {
		String str = jedis.lset(key, index, value);
		return str;
	}

	public Long lrem(String key, Long count, String value) {
		Long l = jedis.lrem(key, count, value);
		return l;
	}

	public String ltrim(String key, Long start, Long end) {
		String str = jedis.ltrim(key, start, end);
		return str;
	}

	public String lpop(String key) {
		String str = jedis.lpop(key);
		return str;
	}

	public String rpop(String key) {
		String str = jedis.rpop(key);
		return str;
	}

	public String rpoplpush(String srckey, String dstkey) {
		String str = jedis.rpoplpush(srckey, dstkey);
		return str;
	}

	public String lindex(String key, Long index) {
		String str = jedis.lindex(key, index);
		return str;
	}

	public Long llen(String key) {
		Long l = jedis.llen(key);
		return l;
	}

	public Long hset(int seconds, String key, String field, String value) {
		Long l = jedis.hset(key, field, value);
		jedis.expire(key, seconds);
		return l;
	}

	public Long hset(String key, String field, String value) {
		Long l = jedis.hset(key, field, value);
		return l;
	}

	public String hget(String key, String field) {
		String str = jedis.hget(key, field);
		return str;
	}

	public Long hsetnx(String key, String field, String value) {
		Long l = jedis.hsetnx(key, field, value);
		return l;
	}

	public Long hsetnx(int seconds, String key, String field, String value) {
		Long l = jedis.hsetnx(key, field, value);
		if (l != 0) {
			jedis.expire(key, seconds);
		}
		return l;
	}

	public String hmset(int seconds, String key, Map<String, String> hash) {
		String str = jedis.hmset(key, hash);
		jedis.expire(key, seconds);
		return str;
	}

	public String hmset(String key, Map<String, String> hash) {
		String str = jedis.hmset(key, hash);
		return str;
	}

	public List<String> hmget(String key, String... fields) {
		List<String> list = jedis.hmget(key, fields);
		return list;
	}

	public Long hincrby(String key, String field, Long value) {
		Long l = jedis.hincrBy(key, field, value);
		return l;
	}

	public Double hincrByFloat(String key, String field, Double value) {
		Double l = jedis.hincrByFloat(key, field, value);
		return l;
	}

	public Boolean hexists(String key, String field) {
		Boolean flag = jedis.hexists(key, field);
		return flag;
	}

	public Long hlen(String key) {
		Long l = jedis.hlen(key);
		return l;
	}

	public Long hdel(String key, String... fields) {
		Long l = jedis.hdel(key, fields);
		return l;
	}

	public Set<String> hkeys(String key) {
		Set<String> set = jedis.hkeys(key);
		return set;
	}

	public List<String> hvals(String key) {
		List<String> list = jedis.hvals(key);
		return list;
	}

	public Map<String, String> hgetAll(String key) {
		Map<String, String> map = jedis.hgetAll(key);
		return map;
	}

	public Long zadd(String key, Double score, String member) {
		Long l = jedis.zadd(key, score, member);
		return l;
	}

	public Long zadd(String key, Map<String, Double> scoreMembers) {
		Long l = jedis.zadd(key, scoreMembers);
		return l;
	}

	public Long zadd(int seconds, String key, Double score, String member) {
		Long l = jedis.zadd(key, score, member);
		jedis.expire(key, seconds);
		return l;
	}

	public Long zadd(int seconds, String key, Map<String, Double> scoreMembers) {
		Long l = jedis.zadd(key, scoreMembers);
		jedis.expire(key, seconds);
		return l;
	}

	public Long zrem(String key, String... members) {
		Long l = jedis.zrem(key, members);
		return l;
	}

	public Double zincrby(String key, Double score, String member) {
		Double d = jedis.zincrby(key, score, member);
		return d;
	}

	public Long zrank(String key, String member) {
		Long l = jedis.zrank(key, member);
		return l;
	}

	public Long zrevrank(String key, String member) {
		Long l = jedis.zrevrank(key, member);
		return l;
	}

	public Set<String> zrevrange(String key, Long start, Long end) {
		Set<String> set = jedis.zrevrange(key, start, end);
		return set;
	}

	public Set<String> zrange(String key, Long start, Long end) {
		Set<String> set = jedis.zrange(key, start, end);
		return set;
	}

	public Set<String> zrangebyscore(String key, Double min, Double max) {
		Set<String> set = jedis.zrangeByScore(key, min, max);
		return set;
	}

	public Set<String> zrangebyscore(String key, String min, String max) {
		Set<String> set = jedis.zrangeByScore(key, min, max);
		return set;
	}

	public Set<String> zrangebyscore(String key, String min, String max, int offset, int count) {
		Set<String> set = jedis.zrangeByScore(key, min, max, offset, count);
		return set;
	}

	public Set<String> zrangebyscore(String key, Double min, Double max, int offset, int count) {
		Set<String> set = jedis.zrangeByScore(key, min, max, offset, count);
		return set;
	}

	public Long zcount(String key, Double min, Double max) {
		Long l = jedis.zcount(key, min, max);
		return l;
	}

	public Long zcount(String key, String min, String max) {
		Long l = jedis.zcount(key, min, max);
		return l;
	}

	public Long zcard(String key) {
		Long l = jedis.zcard(key);
		return l;
	}

	public Double zscore(String key, String member) {
		Double d = jedis.zscore(key, member);
		return d;
	}

	public Long zremrangeByRank(String key, Long start, Long end) {
		Long l = jedis.zremrangeByRank(key, start, end);
		return l;
	}

	public Long zremrangeByScore(String key, Double start, Double end) {
		Long l = jedis.zremrangeByScore(key, start, end);
		return l;
	}

	public Long zremrangebyscore(String key, String start, String end) {
		Long l = jedis.zremrangeByScore(key, start, end);
		return l;
	}

	public Set<String> keys(String pattern) {
		Set<String> set = jedis.keys(pattern);
		return set;
	}

	public List<String> lrange(String key, Long start, Long end) {
		List<String> list = jedis.lrange(key, start, end);
		return list;
	}

	public String flushDB() {
		String str = jedis.flushDB();
		return str;
	}

	public String flushAll() {
		String str = jedis.flushAll();
		return str;
	}

	public Boolean exists(String key) {
		Boolean flag = jedis.exists(key);
		return flag;
	}

	public Long expire(String key, int seconds) {
		Long l = jedis.expire(key, seconds);
		return l;
	}

	public String info() {
		String info = jedis.info();
		return info;
	}

	public String select(int dbIndex) {
		String select = jedis.select(dbIndex);
		return select;
	}

	public long ttl(String key) {
		long second = jedis.ttl(key);
		return second;
	}

	public List<String> time() {
		List<String> timeList = jedis.time();
		return timeList;
	}
	
	public Long getMicrosecond(){
		try {
			List<String> time = jedis.time();
			long millisecond = Long.valueOf(time.get(0));
			long microsecond = millisecond * 1000*1000 + Long.valueOf(time.get(1));
			return microsecond;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
}
